package cn.biplam.front.template.control.table;

import java.util.ArrayList;

import cn.biplam.common.wrapper.ErrorMessage;
import cn.biplam.front.html.HtmlDiv;
import cn.biplam.front.html.HtmlTable;
import cn.biplam.front.html.HtmlTableCell;
import cn.biplam.front.html.HtmlTableRow;
import cn.biplam.front.html.HtmlTableTh;
import cn.biplam.front.html.base.Html;
import cn.biplam.front.html.base.HtmlWindow;
import cn.biplam.front.html.base.Const.Border_Style;
import cn.biplam.front.html.base.Const.Length_Unit;
import cn.biplam.front.template.Template;

/**
 * 表格基础类
 * @author XiaoRuxing
 * @version 1.0
 */
public class Table implements Template{
	
	/** 用户放置table的DIV */
	private HtmlDiv tableContainer;
	/**表格页面ID */
	private String ID;
	/** 表格容器 */
	private HtmlTable table;
	/** 当前操作行 */
	private ArrayList<HtmlTableCell> currentRow;
	/** 行容器 */
	private ArrayList<ArrayList<HtmlTableCell>> cells;
	private ArrayList<Html> extendElements;
	
	/** 自动生成ID标示 */
	private boolean autoIdFlag;
	
	/** 是否绑定显示效果脚本 */
	private boolean bindViewScript=true;
	
	/** 单元格类型 */
	public enum Table_Cell_Type{
		/** 普通单元格 */
		TD,
		/** 标题单元格 */
		TH
	}
	
	/** 默认单元格类型TD */
	private Table_Cell_Type defaultType=Table_Cell_Type.TD;
	
	public Table() throws ErrorMessage{
		this(null);
	}
	
	/**
	 * 	构造方法
	 * @param tableId 表格ID
	 * @throws ErrorMessage
	 */
	public Table(String tableId) throws ErrorMessage{
		this(tableId,null);
	}
	
	public Table(String tableId,String cssId) throws ErrorMessage{
		this.ID=tableId;
		if(tableId!=null){
			this.table=new HtmlTable(this.ID+"b",cssId);
		}else{
			this.table = new HtmlTable(null,cssId);
		}
		_init();
	}
	 
	/**
	 * @throws ErrorMessage 
	 * 初始化表格 
	 */
	private void _init() throws ErrorMessage{
		tableContainer = new HtmlDiv(this.ID);
		autoIdFlag=true;
		cells=new ArrayList<ArrayList<HtmlTableCell>>();
		currentRow=new ArrayList<HtmlTableCell>();
		
		this.extendElements = new ArrayList<Html>();
		table.setCellPadding("0");
		table.setCellSpaceing("0");
	}
	
	/**
	 * 放入非行列的额外隐藏对象
	 * @param html
	 * @throws ErrorMessage
	 */
	public void putExtend(Html html) throws ErrorMessage{
		extendElements.add(html);
	}
	
	/**
	 * 插入单元格,在最后一行行尾插入
	 * @param colContent
	 * @throws ErrorMessage 
	 */
	public void put(Html colContent) throws ErrorMessage{
		put(colContent,null,null);
	}
	
	/**
	 * 插入单元格,在最后一行行尾插入
	 * @param colContent
	 * @throws ErrorMessage 
	 */
	public void put(Html colContent,Table_Cell_Type cellType) throws ErrorMessage{
		put(colContent,null,null,cellType);
	}
	
	/**
	 * 在指定行尾插入单元格，行下标不能超过行数
	 * @param colContent  单元格内容
	 * @param rowIndex      行数 
	 * @throws ErrorMessage 
	 */
	public void put(Html colContent,int rowIndex) throws ErrorMessage{
		put(colContent,rowIndex,null,null);
	}
	
	/**
	 * 在指定行尾插入单元格，行下标不能超过行数
	 * @param colContent  单元格内容
	 * @param rowIndex      行数 
	 * @throws ErrorMessage 
	 */
	public void put(Html colContent,int rowIndex,Table_Cell_Type cellType) throws ErrorMessage{
		put(colContent,rowIndex,null,null,cellType);
	}
	
	/**
	 * 在指定行的指定列插入单元格，行下标不能超过行数，列下标不能超过列数
	 * @param colContent 单元格内容
	 * @param rowIndex     行数
	 * @param colIndex     列数 
	 * @throws ErrorMessage 
	 */
	public void put(Html colContent,int rowIndex,int colIndex) throws ErrorMessage{
		put(colContent,rowIndex,colIndex,null,null,null);
	}
	
	/**
	 * 在指定行的指定列插入单元格，行下标不能超过行数，列下标不能超过列数
	 * @param colContent 单元格内容
	 * @param rowIndex     行数
	 * @param colIndex     列数 
	 * @throws ErrorMessage 
	 */
	public void put(Html colContent,int rowIndex,int colIndex,Table_Cell_Type cellType) throws ErrorMessage{
		put(colContent,rowIndex,colIndex,null,null,cellType);
	}
	
	/**
	 * 插入单元格,在最后一行行尾插入，并设置单元格占用格数
	 * @param colContent 单元格内容
	 * @param colspan    单元格所占列数
	 * @throws ErrorMessage 
	 */
	public void put(Html colContent,String colspan) throws ErrorMessage{
		put(colContent,colspan,null);
	}
	
	/**
	 * 插入单元格,在最后一行行尾插入，并设置单元格占用格数
	 * @param colContent 单元格内容
	 * @param colspan    单元格所占列数
	 * @param rowspan    单元格所占行数
	 * @throws ErrorMessage 
	 */
	public void put(Html colContent,String colspan,String rowspan) throws ErrorMessage{
		put(colContent,colspan,rowspan,null);
	}
	
	/**
	 * 插入单元格,在最后一行行尾插入，并设置单元格占用格数
	 * @param colContent 单元格内容
	 * @param colspan    单元格所占列数 
	 * @param rowspan    单元格所占行数
	 * @param cellType   单元格类型
	 * @throws ErrorMessage
	 */
	public void put(Html colContent,String colspan,String rowspan,Table_Cell_Type cellType) throws ErrorMessage{
		int rowIndex=-1;
		int colIndex=-1;
		if(cells.size()>0){
			rowIndex=cells.size()-1;
			colIndex=cells.get(rowIndex).size();
		}else{
			rowIndex=0;
			colIndex=0;
		}
		put(colContent,rowIndex,colIndex,colspan,rowspan,cellType);
	}
	
	/**
	 * 在指定行尾插入单元格，并设置单元格占用格数，行下标不能超过行数，列下标不能超过列数
	 * @param colContent 内容
	 * @param rowIndex   行索引
	 * @param colspan    列数
	 * @throws ErrorMessage 
	 */
	public void put(Html colContent,int rowIndex,String colspan) throws ErrorMessage{
		put(colContent,rowIndex,colspan,null);
	}
	
	/**
	 * 在指定行尾插入单元格，并设置单元格占用格数，行下标不能超过行数，列下标不能超过列数
	 * @param colContent 内容
	 * @param rowIndex  行索引
	 * @param colspan   列数
	 * @param rowspan   行数
	 * @throws ErrorMessage 
	 */
	public void put(Html colContent,int rowIndex,String colspan,String rowspan) throws ErrorMessage{
		put(colContent,rowIndex,colspan,rowspan,null);
	}
	
	/**
	 * 在指定行尾插入单元格，并设置单元格占用格数，行下标不能超过行数，列下标不能超过列数
	 * @param colContent
	 * @param rowIndex
	 * @param colspan
	 * @throws ErrorMessage 
	 */
	public void put(Html colContent,int rowIndex,String colspan,String rowspan,Table_Cell_Type cellType) throws ErrorMessage{
		if(rowIndex>cells.size()){
			throw new ErrorMessage("out of bound");
		}
		int colIndex=-1;
		if(cells.size()==rowIndex){
			colIndex=0;
		}else{
			colIndex=cells.get(rowIndex).size();
		}
		put(colContent,rowIndex,colIndex,colspan,rowspan,cellType);
	}
	
	/**
	 * 在指定行的指定列插入单元格，并设置单元格占用格数，行下标不能超过行数，列下标不能超过列数
	 * @param colContent
	 * @param rowIndex
	 * @param colIndex
	 * @param colspan
	 * @throws ErrorMessage 
	 */
	public void put(Html colContent,int rowIndex,int colIndex,String colspan) throws ErrorMessage{
		put(colContent,rowIndex,colIndex,colspan,null);
	}
	
	/**
	 * 在指定行的指定列插入单元格，并设置单元格占用格数，行下标不能超过行数，列下标不能超过列数
	 * @param colContent
	 * @param rowIndex
	 * @param colIndex
	 * @param colspan
	 * @throws ErrorMessage 
	 */
	public void put(Html colContent,int rowIndex,int colIndex,String colspan,String rowspan) throws ErrorMessage{
		put(colContent,rowIndex,colIndex,colspan,rowspan,null);
	}
	
	/**
	 * 在指定行的指定列插入单元格，并设置单元格占用格数，行下标不能超过行数，列下标不能超过列数
	 * @param colContent
	 * @param rowIndex
	 * @param colIndex
	 * @param colspan
	 * @throws ErrorMessage 
	 */
	public void put(Html colContent,int rowIndex,int colIndex,String colspan,String rowspan,Table_Cell_Type cellType) throws ErrorMessage{
		
		/** 创建单元格 */
		HtmlTableCell cell=_generatorTableCell(colContent, rowIndex, colIndex, 
				colspan, rowspan, cellType);
		_put(cell,rowIndex,colIndex);
	}
	
	private HtmlTableCell _generatorTableCell(Html colContent,int rowIndex,int colIndex,
			String colspan,String rowspan,
			Table_Cell_Type cellType) throws ErrorMessage{
		HtmlTableCell cell=null;
		if(cellType==null){
			cellType=defaultType;
		}
		
		switch(cellType){
		case TD:
			if(autoIdFlag){
				cell=new HtmlTableCell(new ElementID(this.ID,rowIndex,colIndex).toString());
			}else{
				cell=new HtmlTableCell();
			}
			break;
		case TH:
			cell=new HtmlTableTh();
			break;
		}
		
		cell.put(colContent);
		if(colspan!=null){
			cell.setColSpan(colspan);
		}
		if(rowspan!=null){
			cell.setRowSpan(rowspan);
		}
		return cell;
	}
	
	/**
	 *  插入行
	 * @param rowIndex 行索引(范围:0~表格行数)
	 */
	public void insertRow(int rowIndex) throws ErrorMessage{
		/** 创建单元格 */
		this.currentRow=new ArrayList<HtmlTableCell>();
		this.cells.add(rowIndex,currentRow);
	}
	
	/**
	 * 替换指定单元格
	 * @param colContent   单元格内容
	 * @param rowIndex   行下标 从0开始
	 * @param colIndex   列下标 从0开始
	 * @throws ErrorMessage
	 */
	public void replaceCol(Html colContent,int rowIndex,int colIndex) throws ErrorMessage{
		ArrayList<HtmlTableCell> currow = cells.get(rowIndex);
		HtmlTableCell cell=_generatorTableCell(colContent, rowIndex, colIndex, 
				null, null, null);
		currow.set(colIndex, cell);
	}
	
	/**
	 * 插入单元格到表格中的指定位置，行下标不能超过行数，列下标不能超过列数
	 * @param cell     单元格    
	 * @param rowIndex   行下标 
	 * @param colIndex   列下标
	 * @throws ErrorMessage
	 */
	private void _put(HtmlTableCell cell,int rowIndex,int colIndex) throws ErrorMessage{
		
		int rowSize=cells.size();
		if(rowIndex>rowSize){
			throw new ErrorMessage("Out of bound(rowIndex="+rowIndex+",rowSize="+rowSize+")");
		}else if(rowIndex==rowSize){
			currentRow=new ArrayList<HtmlTableCell>();
			cells.add(currentRow);
		}else{
			currentRow=cells.get(rowIndex);
		}
		
		int colSize=currentRow.size();
		if(colIndex>colSize){
			throw new ErrorMessage("Out of bound(colIndex="+colIndex+",colSize="+colSize+")");
		}else if(colIndex==colSize){
			currentRow.add(cell);
		}else{
			currentRow.add(colIndex,cell);
		}
	}
	
	/**
	 * 设置表格宽度
	 * @param width
	 * @throws ErrorMessage
	 */
	public void setWidth(String width) throws ErrorMessage{
		table.setWidth(width);
	}
	
	/**
	 * 设置表格在布局中所占宽度
	 * @param width
	 * @throws ErrorMessage 
	 */
	public void setClientWidth(String width) throws ErrorMessage{
		tableContainer.setStyleWidth(width);
	}
	
	/**
	 * 设置表格在布局中所占宽度
	 * @param width
	 * @throws ErrorMessage 
	 */
	public void setClientWidth(String width,Length_Unit unit) throws ErrorMessage{
		tableContainer.setStyleWidth(width,unit);
	}
	
	/**
	 * 设置表格在布局中所占宽度 
	 * @param height
	 * @throws ErrorMessage
	 */
	public void setClientHeight(String height) throws ErrorMessage{
		tableContainer.setStyleHeight(height);
	}
	
	/**
	 * 设置表格高度
	 * @param height
	 * @throws ErrorMessage
	 */
	public void setHeight(String height) throws ErrorMessage{
		table.setHeight(height);
	}
	
	/**
	 * 设置单元格宽度
	 * @param width 宽度
	 * @param row   行
	 * @param col   列
	 * @throws ErrorMessage
	 */
	public void setColWidth(String width,int row,int col) throws ErrorMessage{
		setColWidth(width, row, col, Length_Unit.px);
	}
	
	/**
	 * 设置单元格宽度
	 * @param width 宽度
	 * @param row   行
	 * @param col	列
	 * @param unit  单位
	 * @throws ErrorMessage
	 */
	public void setColWidth(String width,int row,int col,Length_Unit unit) throws ErrorMessage{
		HtmlTableCell cell=cells.get(row).get(col);
		if(cell==null){
			throw new ErrorMessage("Unknown cell(row="+row+",col="+col+")");
		}else{
			this.cells.get(row).get(col).setWidth(width,unit);
		}
	}
	
	/**
	 * 设置表格宽度
	 * @param width
	 * @param unit
	 * @throws ErrorMessage
	 */
	public void setWidth(String width,Length_Unit unit) throws ErrorMessage{
		table.setWidth(width, unit);
	}
	
	/**
	 * 设置表格高度
	 * @param height
	 * @param unit
	 * @throws ErrorMessage
	 */
	public void setHeight(String height,Length_Unit unit) throws ErrorMessage{
		table.setHeight(height, unit);
	}
	
	/**
	 *  设置是否绑定显示效果脚本
	 * @param isBind
	 */
	public void setBindViewScript(boolean isBind){
		this.bindViewScript = isBind;
	}
	
	/**
	 * 放入表格
	 * @param table 表格
	 * @throws ErrorMessage
	 */
	public void putTable(Table table) throws ErrorMessage{
		this.tableContainer.put(table.get());
	}
	
	/**
	 * 生成表格
	 * @throws ErrorMessage
	 */
	private void _generatorTable() throws ErrorMessage{
		for(int i=0;i<cells.size();i++){
			ArrayList<HtmlTableCell> row=cells.get(i);
			/** 设置行ID */
			HtmlTableRow tr=null;
			if(autoIdFlag){
				tr=new HtmlTableRow(new ElementID(this.ID,i).toString());
			}else{
				tr=new HtmlTableRow();
			}
			for(HtmlTableCell col:row){
				tr.put(col);
			}
			table.put(tr);
		}
	}
	
	/**
	 * 设置自动生成行ID和单元格ID
	 * @param autoIdFlag
	 */
	public void setAutoIdFlag(boolean autoIdFlag) {
		this.autoIdFlag = autoIdFlag;
	}
	
	/**
	 * 设置指定单元格边框
	 * @param row   行下标
	 * @param col   列下标
	 * @param width 边框宽度
	 * @param style 边框类型 
	 * @param color 边框颜色
	 * @throws ErrorMessage
	 */
	public void setColBorder(int row, int col,String width,
			Border_Style style,String color) throws ErrorMessage{
		HtmlTableCell cell=cells.get(row).get(col);
		if(cell==null){
			//TODO 错误定义
			throw new ErrorMessage("未知列");
		}else{
			this.cells.get(row).get(col).setBorder(width, style, color);
		}
	}
	
	/**
	 * 设置单元格的CSS样式属性值
	 * @param row   行下标
	 * @param col   列下标
	 * @param styleName			样式属性名称
	 * @param styleValue		样式属性值
	 * @throws ErrorMessage
	 */
	public void setColStyle(int row, int col,String styleName,String styleValue) throws ErrorMessage{
		HtmlTableCell cell=cells.get(row).get(col);
		if(cell==null){
			//TODO 错误定义
			throw new ErrorMessage("未知列");
		}else{
			this.cells.get(row).get(col).setStyle(styleName, styleValue);
		}
	}
	
	/**
	 * 设置单元格的CSS样式属性值
	 * @param row   行下标
	 * @param col   列下标
	 * @param styleName			样式属性名称
	 * @param styleValue		样式属性值
	 * @throws ErrorMessage
	 */
	public void setStyle(String styleName,String styleValue) throws ErrorMessage{
		this.table.setStyle(styleName, styleValue);
	}
	
	/**
	 * 获取列
	 * @param i
	 * @return
	 * @throws ErrorMessage
	 */
	public HtmlWindow getRow(int i) throws ErrorMessage{
		if(i>this.cells.size()){
			throw new ErrorMessage("Row index "+i+" is overflow the table size!");
		}else{
			return (HtmlWindow)this.table.get(i);
		}
	}
	
	/**
	 * @return 当前表格行数
	 */
	public int getRowNumb(){
		return this.cells.size();
	}
	
	/**
	 *  获取表格ID
	 * @return 当前表格对象在HtmlTable外面包装了一个DIV,返回HtmlTable对象的ID
	 */
	public String getInnertTableId(){
		return this.table.getID();
	}
	
	/**
	 * 获取表格
	 * @return 表格的html描述
	 * @throws ErrorMessage
	 */
	public HtmlWindow get() throws ErrorMessage{
		_generatorTable();
		tableContainer.put(table);
		_setExtent();
		//设置绑定表格显示脚本
		if(table.getID()!=null
				&& this.bindViewScript){
			table.bind("tb('"+table.getID()+"');");
		}
		return tableContainer;
	}
	
	/**
	 * 设置附加元素
	 * @throws ErrorMessage
	 */
	private void _setExtent() throws ErrorMessage{
		for(Html ext: this.extendElements){
			this.tableContainer.put(ext);
		}
	}
	
	/**
	 * 返回表格行对象的页面容器ID
	 * @param tableId	表格的页面容器ID
	 * @param row		行编号(0-n)
	 * @return	String
	 */
	public static String GetRowID(String tableId,int row){
		StringBuilder sb = new StringBuilder(tableId);
		sb.append('[');
		sb.append(row);
		sb.append(']');
		return sb.toString();
	}
}
